home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / mail / mh / vmail / vmail.2of3 / move.c < prev    next >
C/C++ Source or Header  |  1991-04-05  |  10KB  |  400 lines

  1. #ifndef lint
  2. static char *RCS_move_c = "$Id: move.c,v 1.3 91/03/08 15:57:57 jamesp Exp $";
  3. #endif
  4.  
  5. /* --------------------
  6.     vmail -- move.c
  7.  
  8.     Routines to delete or move a mail item from current folder.
  9.  
  10.     Copyright (C) J. Zobel, University of Melbourne, October 1987.
  11. -------------------- */
  12.  
  13. #include "defs.h"
  14. #include <errno.h>
  15.  
  16. static char prevfile[LEN] = "";
  17.  
  18. extern int errno;
  19.  
  20. /* --------------------
  21.     Move current item to folder prevfile (get_name = false) or as read from
  22.     terminal (get_name = true).
  23. -------------------- */
  24. void
  25. move_item(get_name)
  26.     bool    get_name;
  27. {
  28.     char    *s, str[LEN], str2[LEN];
  29.     folder    f, new_folder(), create_folder();
  30.     item    m;
  31.     bool    redraw;                        /* true if screen to be refreshed */
  32.     int        fdi, fdo, i = FIRST-1, num, N;
  33.  
  34.         /* get name if required */
  35.     if(get_name || *prevfile == '\0') {
  36.         get_string("folder? ", str);
  37.         if(*str == '\0') {
  38.             addstatus("no name given for folder", true);
  39.             return;
  40.         }
  41.         (void)strcpy(prevfile, str);
  42.     } else
  43.         (void)strcpy(str, prevfile);
  44.         /* find first page of named folder */
  45.     (void)sprintf(str2, "refiling to %s ...", str);
  46.     addstatus(str2, false);
  47.     GOTO_NAME(f, str);
  48.     if(f == (folder) NULL) {    /* create folder */
  49.         f = create_folder(str);
  50.         if(f == (folder) NULL)
  51.             return;
  52.     } else {
  53.         if(f->name == curflr->name) {
  54.             addstatus("can't move item to current folder", true);
  55.             return;
  56.         }
  57.         if(f->valid) {        /* goto last mail item in folder */
  58.             LAST_OF_NAME(f);
  59.             for(i=FIRST, m=f->mail ; m->next != (item) NULL ; i++, m=m->next)
  60.                 ;
  61.         }
  62.     }
  63.         /* remember current location of mail */
  64.     m = curmail;
  65.     num = curmail->number;
  66.     s = curflr->name;
  67.         /* delete item from current folder, update current folder & screen */
  68.     redraw = change_item(true);
  69.     if(f->valid)        /* update structures of mail items */
  70.         if(i > lines) {
  71.                 /* create new folder record */
  72.             f = new_folder(f);
  73.             f->mail = f->last = m;
  74.             m->prev = m->next = (item) NULL;
  75.             N = f->prev->last->number;
  76.         } else {
  77.                 /* insert at end of list of mail items */
  78.             m->prev = f->last; m->next = (item) NULL;
  79.             f->last->next = m;
  80.             f->last = m;
  81.             N = m->prev->number;
  82.         }
  83.     else
  84.         N = next_vacant(f);
  85. /* to avoid race between "send" or other process in background and vmail
  86.    foreground, compute next free slot, dont just use given value 
  87. */
  88.     (void)sprintf(str2, "%s/%s/%d", mail_dir, f->name, N);
  89.         /* loop until unused file name found */
  90.     for(errno=0 ; (fdo = open(str2, O_WRONLY|O_CREAT|O_EXCL, 0644)) < 0
  91.                                             && errno == EEXIST ; errno=0) {
  92.         N = N + 1;
  93.         (void)sprintf(str2, "%s/%s/%d", mail_dir, f->name, N);
  94.     }
  95.     if(f->valid)
  96.         m->number = N;
  97.     (void)sprintf(str, "%s/%s/%d", mail_dir, s, num);
  98.     fdi = open(str, O_RDONLY);
  99.     while((i = read(fdi, str2, LEN)) > 0)    /* copy original to new */
  100.         (void)write(fdo, str2, i);
  101.     (void)close(fdi);
  102.     (void)close(fdo);
  103.     (void)unlink(str);                            /* remove original */
  104.     if(redraw)
  105.         display_page();
  106.     else {
  107.         add_page_header(str);
  108.         move(y, 0);
  109.         refresh();
  110.     }
  111.     addstatus("refiled", true);
  112.     if(curflr == (folder) NULL) {
  113.         to_normal();
  114.         exit(1);
  115.     }
  116. }
  117.  
  118.  
  119. /* --------------------
  120.     Delete count items.
  121. -------------------- */
  122. void
  123. delete_item(count)
  124.     int        count;
  125. {
  126.     bool    redraw = false;
  127.     item    m;
  128.     char    str[LEN];
  129.  
  130.     for( ; count > 0 ; count--) {
  131.         m = curmail->next;
  132.         redraw = change_item(false);
  133.         if(redraw || m != curmail) /* on new page, or last item deleted */
  134.             break;
  135.     }
  136.     if(redraw)
  137.         display_page();
  138.     else {
  139.         add_page_header(str);
  140.         move(y, 0);
  141.         refresh();
  142.     }
  143. }
  144.  
  145.  
  146. /* --------------------
  147.     Structure for deleted item.
  148. -------------------- */
  149. struct {
  150.     folder flr;
  151.     int number;
  152. } deleted = {(folder) NULL, 0};
  153.  
  154.  
  155. /* --------------------
  156.     Either delete (do_move = false) or prepare to move (do_move = true) item.
  157.     Delete item from current folder, update screen, find new current folder
  158.     if current folder has become empty.
  159. -------------------- */
  160. bool
  161. change_item(do_move)
  162.     bool    do_move;
  163. {
  164.     item    tmp, m = curmail;
  165.     folder    F, p, f = curflr, pval, nval;
  166.     char    s1[LEN], s2[LEN];
  167.     bool    redraw, doexit = false;
  168.  
  169.     if(curmail->next == (item) NULL && curmail->prev == (item) NULL) {
  170.             /* have last item in page */
  171.         redraw = true;
  172.         pval = curflr->prev; PREV_VALID(pval);
  173.         nval = curflr->next; NEXT_VALID(nval);
  174.         if(pval == (folder) NULL && nval == (folder) NULL) {
  175.                         /* no more active pages */
  176.             if(! do_move)
  177.                 addstatus("Deleting last active mail item -- bye", true);
  178.             doexit = true;
  179.         } else {
  180.                 /* update pages, pagenum */
  181.             for(p=curflr->prev ; p != (folder) NULL && p->name == curflr->name
  182.                                                                     ; p=p->prev)
  183.                 p->pages -= 1;
  184.             for(p=curflr->next ; p != (folder) NULL && p->name == curflr->name
  185.                                                                     ; p=p->next)
  186.                 p->pages -= 1, p->pagenum -= 1;
  187.                 /* find next active page, drop current page from list */
  188.             if(curflr->prev != (folder) NULL)
  189.                 curflr->prev->next = curflr->next;
  190.             else
  191.                 folders = curflr->next;
  192.             if(curflr->next != (folder) NULL)
  193.                 curflr->next->prev = curflr->prev;
  194.             /*
  195.              * If the previous page is from the same folder,
  196.              * move to last item on that page.  Otherwise,
  197.              * move to first page of next folder if it is
  198.              * available, else move to first page of previous
  199.              * folder if it is available.
  200.              */
  201.             if (pval != (folder) NULL && pval->name == curflr->name) {
  202.                 curflr = pval;
  203.                 curmail = curflr->mail;
  204.                 for ( ; curmail->next != (item) NULL; y++)
  205.                 curmail = curmail->next;
  206.             }
  207.             else
  208.             {
  209.                 curflr = (nval == (folder) NULL) ? pval : nval;
  210.                 curmail = curflr->mail;
  211.             }
  212.         }
  213.     } else {
  214.         redraw = false;
  215.         deleteline();
  216.             /* move first item from next to current */
  217.         if(curflr->next != (folder) NULL && curflr->name == curflr->next->name)
  218.             show_title(s1, FIRST+lines-1, curflr->next->mail);
  219.         for(p=curflr->next ; p != (folder) NULL && p->name == curflr->name ;
  220.                                                                     p=p->next) {
  221.             tmp = p->mail;
  222.             p->mail = tmp->next;
  223.             if(p->mail == (item) NULL) { /* remove folder from list */
  224.                 p->prev->next = p->next;
  225.                 if(p->next != (folder) NULL)
  226.                     p->next->prev = p->prev;
  227.                     /* update page counts */
  228.                 for(F=p->prev ; F != (folder) NULL && F->name == p->name
  229.                                                                     ; F=F->prev)
  230.                     F->pages -= 1;
  231.             } else
  232.                 p->mail->prev = (item) NULL;
  233.             p->prev->last->next = tmp;
  234.             tmp->prev = p->prev->last;
  235.             tmp->next = (item) NULL;
  236.             p->prev->last = tmp;
  237.         }
  238.             /* delete item from linked list of items */
  239.         if(m->prev == (item) NULL)
  240.             curflr->mail = m->next;
  241.         else
  242.             m->prev->next = m->next;
  243.         if(m->next == (item) NULL) {
  244.             curflr->last = m->prev;
  245.             curmail = m->prev;
  246.             y--;
  247.         } else {
  248.             m->next->prev = m->prev;
  249.             curmail = m->next;
  250.         }
  251.         move(y, 0);
  252.     }
  253.     if(! do_move) {
  254.         deleted.flr = f;
  255.         deleted.number = m->number;
  256.         (void)sprintf(s1, "%s/%s/%d", mail_dir, f->name, m->number);
  257.         (void)sprintf(s2, "%s/%s/#%d", mail_dir, f->name, m->number);
  258.         (void)rename(s1, s2);
  259.         if(doexit) {
  260.             to_normal();
  261.             exit(0);
  262.         }
  263.     }
  264.     return(redraw);
  265. }
  266.  
  267.  
  268. /* --------------------
  269.     Create folder of given name if user agrees, creating directory and
  270.     entry in linked list of folders.
  271. -------------------- */
  272. folder
  273. create_folder(str)
  274.     char    *str;
  275. {
  276.     struct stat statbuf;
  277.     char    str2[LEN], c;
  278.     folder    fnew, p, f;
  279.  
  280.     squash(str);
  281.     (void)sprintf(str2, "%s does not exist (or is empty) - create? ", str);
  282.     mvaddstr(STATUS, 0, str2); refresh();
  283.     c = getchar();
  284.     move(STATUS, 0); clrtoeol(); move(y, 0); refresh();
  285.     if(c != 'y')
  286.         return((folder) NULL);
  287.     for(p=(folder) NULL, f=folders ; f != (folder) NULL &&
  288.                             strcmp(str, f->name) > 0 ; p=f, f=f->next)
  289.         ;
  290.         /* create physical folder */
  291.     (void)sprintf(str2, "%s/%s", mail_dir, str);
  292.     if(stat(str2, &statbuf)) {        /* doesn't exist */
  293.         if(mkdir(str2, folder_protect)) {
  294.             addstatus("Cannot make folder", true);
  295.             return((folder) NULL);
  296.         }
  297.     } else
  298.         if(!(statbuf.st_mode & S_IREAD) || !(statbuf.st_mode & S_IWRITE)
  299.                                     || !(statbuf.st_mode & S_IEXEC)) {
  300.                 addstatus("Cannot write in folder", true);
  301.                 return((folder) NULL);
  302.         }
  303.             /* make a new folder record, insert it */
  304.     fnew = NEW(mail_folder);
  305.     fnew->name = NEWSTR(strlen(str)+1);
  306.     (void)strcpy(fnew->name, str);
  307.     fnew->mail = fnew->last = (item) NULL;
  308.     fnew->next = fnew->prev = (folder) NULL;
  309.     fnew->pages = fnew->pagenum = 1;
  310.     fnew->valid = false;
  311.     if(p == (folder) NULL) {
  312.         fnew->next = folders;
  313.         folders->prev = fnew;
  314.         folders = fnew;
  315.     } else {
  316.         p->next = fnew;
  317.         if(f != (folder) NULL)
  318.             f->prev = fnew;
  319.         fnew->prev = p;
  320.         fnew->next = f;
  321.     }
  322.     return(fnew);
  323. }
  324.  
  325.  
  326. /* --------------------
  327.     Crude undo.  Sophisticated undo rather too painful to code.
  328. -------------------- */
  329. void
  330. undo()
  331. {
  332.     folder    f = deleted.flr, p;
  333.     char    s1[LEN], s2[LEN];
  334.  
  335.     if(f == (folder) NULL) {
  336.         addstatus("nothing to undo", true);
  337.         return;
  338.     } else {
  339.         addstatus("undoing ...", true);
  340.         deleted.flr = (folder) NULL;
  341.     }
  342.     (void)sprintf(s1, "%s/%s/#%d", mail_dir, f->name, deleted.number);
  343.     (void)sprintf(s2, "%s/%s/%d", mail_dir, f->name, deleted.number);
  344.     (void)rename(s1, s2);
  345.         /* find first page of folder */
  346.     p = f; FRST_OF_NAME(p);
  347.         /* find last page of folder */
  348.     LAST_OF_NAME(f);
  349.     curflr = p;
  350.     p->next = f->next;
  351. /* should free old folder/mail records */
  352. /*    p->valid = false; */
  353.     p->mail = p->last = (item) NULL;
  354.     p->pagenum = p->pages = 1;
  355.     if(p->next != (folder) NULL)
  356.         p->next->prev = p;
  357.     (void)find_mail(curflr, false);
  358.     curmail = curflr->mail;
  359.     y = FIRST;
  360.     display_page();
  361. }
  362.  
  363.  
  364. /* --------------------
  365.     Pack current folder.  Unsets "deleted" if last removed record was
  366.     on current folder.
  367. -------------------- */
  368. void
  369. pack_folder()
  370. {
  371.     folder    f = curflr;
  372.     item    m;
  373.     char    path[LEN], s1[LEN], s2[LEN];
  374.     bool    found;
  375.     int        newnum = 1;
  376.  
  377.     addstatus("Packing folder ...", false);
  378.     FRST_OF_NAME(f);
  379.         /* unset undo if packing that folder */
  380.     if(deleted.flr != (folder) NULL && deleted.flr->name == curflr->name)
  381.         deleted.flr = (folder) NULL;
  382.     (void)sprintf(path, "%s/%s/", mail_dir, curflr->name);
  383.     for( ; f != (folder) NULL && f->name == curflr->name ; f=f->next)
  384.         for(m=f->mail ; m != (item) NULL ; m=m->next) {
  385.             for(found=false ; !found && newnum < m->number ; ) {
  386.                 (void)sprintf(s1, "%s%d", path, newnum);
  387.                 if(! access(s1, R_OK))
  388.                     newnum++;
  389.                 else
  390.                     found = true;
  391.             }
  392.             if(found) {
  393.                 (void)sprintf(s2, "%s%d", path, m->number);
  394.                 (void)rename(s2, s1);
  395.                 m->number = newnum;
  396.             }
  397.         }
  398.     display_page();
  399. }
  400.